#include "audiocapturer.h"
#include "spectrumanalyzer.h"  // 添加频谱分析器头文件
#include <QDebug>
#include <functiondiscoverykeys_devpkey.h>

/**
 * 构造函数实现
 * 
 * 使用初始化列表初始化所有成员变量：
 * - 所有 COM 指针设为 nullptr
 * - 状态标志设为 false
 * 
 * 关键点：不在这里初始化 COM，因为：
 * 1. COM 必须在使用它的线程中初始化
 * 2. 构造函数在主线程执行，但 WASAPI 调用在子线程执行
 * 3. 因此 CoInitialize 放在 run() 方法中
 */
AudioCapturer::AudioCapturer(QObject *parent)
    : QThread(parent)
    , m_deviceEnumerator(nullptr)
    , m_device(nullptr)
    , m_audioClient(nullptr)
    , m_captureClient(nullptr)
    , m_waveFormat(nullptr)
    , m_spectrumAnalyzer(nullptr)  // 添加：频谱分析器初始化
    , m_sampleRate(48000)           // 添加：默认采样率
    , m_isCapturing(false)
    , m_stopRequested(false)
{
    // COM 将在工作线程 (run 方法) 中初始化
    // SpectrumAnalyzer 也将在工作线程中创建
}

/**
 * 析构函数实现
 * 
 * 清理步骤：
 * 1. 调用 stopCapture() 设置停止标志
 * 2. 调用 wait() 等待线程结束（最多等待默认超时时间）
 * 3. WASAPI 资源清理在 run() 方法结束时完成
 * 
 * 注意：CoUninitialize 在工作线程中调用，不在这里
 */
AudioCapturer::~AudioCapturer()
{
    stopCapture();
    wait();  // 等待线程安全退出
    // CoUninitialize 将在工作线程中调用
}

/**
 * 停止音频捕获
 * 
 * 通过设置原子变量通知捕获循环退出
 * 线程安全：atomic<bool> 保证可以安全地从任何线程调用
 * 
 * 不会立即停止，而是在下一次循环迭代时检查标志后退出
 */
void AudioCapturer::stopCapture()
{
    m_stopRequested = true;
}

/**
 * 线程主函数
 * 
 * 这是 QThread 的核心方法，在独立线程中执行
 * 
 * 执行流程：
 * 1. 初始化 COM（必须在此线程中初始化）
 * 2. 初始化 WASAPI 音频捕获系统
 * 3. 进入音频捕获循环（持续捕获直到停止请求）
 * 4. 清理 WASAPI 资源
 * 5. 反初始化 COM（必须在同一线程中反初始化）
 * 
 * 错误处理：
 * - COM 初始化失败 → 发出错误信号并返回
 * - WASAPI 初始化失败 → 发出错误信号，清理 COM 并返回
 */
void AudioCapturer::run()
{
    // 步骤1：为此线程初始化 COM
    // COINIT_MULTITHREADED：多线程模式，允许多线程访问 COM 对象
    HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (FAILED(hr)) {
        emit errorOccurred("Failed to initialize COM");
        return;
    }

    // 步骤2：重置状态标志
    m_stopRequested = false;
    m_isCapturing = false;
    
    // 步骤2.5：在子线程中创建频谱分析器（重要！）
    m_spectrumAnalyzer = new SpectrumAnalyzer(20);  // 20个频段
    qDebug() << "SpectrumAnalyzer created in worker thread";

    // 步骤3：初始化 WASAPI
    if(!initializeWASAPI())
    {
        emit errorOccurred("Failed to initialize WASAPI");
        delete m_spectrumAnalyzer;  // 清理分析器
        m_spectrumAnalyzer = nullptr;
        CoUninitialize();  // 初始化失败也要清理 COM
        return;
    }

    // 步骤4：开始捕获
    m_isCapturing = true;
    captureLoop();  // 主循环，直到收到停止请求
    m_isCapturing = false;
    
    // 步骤5：清理资源
    cleanupWASAPI();
    
    // 步骤5.5：清理频谱分析器
    delete m_spectrumAnalyzer;
    m_spectrumAnalyzer = nullptr;
    qDebug() << "SpectrumAnalyzer deleted";
    
    // 步骤6：反初始化 COM
    CoUninitialize();
}

/**
 * 初始化 WASAPI 音频捕获系统
 * 
 * 这是整个音频捕获的核心初始化函数
 * 
 * WASAPI (Windows Audio Session API) 是 Windows Vista+ 的低延迟音频 API
 * Loopback 模式：捕获系统正在播放的音频，而不是从麦克风录音
 * 
 * @return true 成功，false 失败
 */
bool AudioCapturer::initializeWASAPI()
{
    HRESULT hr;  // COM 函数的返回值类型
    
    // ============ 步骤1：创建设备枚举器 ============
    // CoCreateInstance: 创建 COM 对象的标准函数
    // MMDeviceEnumerator: 用于枚举和访问音频设备的 COM 类
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
                         CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
                         (void**)&m_deviceEnumerator);
    if(FAILED(hr)) {
        qDebug() << "Failed to create device enumerator" << hr;
        return false;
    }

    // ============ 步骤2：获取默认音频输出设备 ============
    // eRender: 输出设备（扬声器/耳机），不是 eCapture（麦克风）
    // eConsole: 默认的系统音频设备
    hr = m_deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &m_device);
    if (FAILED(hr)) {
        qDebug() << "Failed to get default audio endpoint";
        return false;
    }

    // ============ 步骤3：激活音频客户端接口 ============
    // 从设备对象获取 IAudioClient 接口
    // IAudioClient: 用于配置和控制音频流的核心接口
    hr = m_device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr,
                           (void**)&m_audioClient);
    if (FAILED(hr)) {
        qDebug() << "Failed to activate audio client";
        return false;
    }

    // ============ 步骤4：获取音频格式信息 ============
    // GetMixFormat: 获取设备当前使用的音频格式
    // 返回的 WAVEFORMATEX 包含：采样率、声道数、位深度等
    hr = m_audioClient->GetMixFormat(&m_waveFormat);
    if (FAILED(hr)) {
        qDebug() << "Failed to get mix format";
        return false;
    }

    // ============ 步骤5：初始化音频客户端（Loopback 模式）============
    // AUDCLNT_SHAREMODE_SHARED: 共享模式（多个应用可同时使用音频设备）
    // AUDCLNT_STREAMFLAGS_LOOPBACK: 关键！使用 Loopback 模式捕获输出音频
    // 10000000: 缓冲区大小（100 纳秒单位）= 1 秒
    hr = m_audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
                                   AUDCLNT_STREAMFLAGS_LOOPBACK,
                                   10000000, // 1 秒缓冲区
                                   0,
                                   m_waveFormat,
                                   nullptr);
    if (FAILED(hr)) {
        qDebug() << "Failed to initialize audio client";
        return false;
    }

    // ============ 步骤6：获取捕获客户端接口 ============
    // IAudioCaptureClient: 用于读取音频数据的接口
    hr = m_audioClient->GetService(__uuidof(IAudioCaptureClient),
                                   (void**)&m_captureClient);
    if (FAILED(hr)) {
        qDebug() << "Failed to get capture client";
        return false;
    }

    // ============ 步骤7：启动音频流 ============
    // 开始填充音频缓冲区，之后就可以读取数据了
    hr = m_audioClient->Start();
    if (FAILED(hr)) {
        qDebug() << "Failed to start audio client";
        return false;
    }

    // 输出音频格式信息（用于调试）
    qDebug() << "WASAPI initialized successfully";
    qDebug() << "Sample Rate:" << m_waveFormat->nSamplesPerSec;      // 通常是 44100 或 48000 Hz
    qDebug() << "Channels:" << m_waveFormat->nChannels;              // 通常是 2（立体声）
    qDebug() << "Bits per sample:" << m_waveFormat->wBitsPerSample;  // 通常是 16 或 32 位

    return true;
}

/**
 * 清理 WASAPI 资源
 * 
 * 按照与初始化相反的顺序释放所有资源
 * COM 对象使用引用计数，必须调用 Release() 来释放
 * 
 * 释放顺序很重要：
 * 1. 先停止音频流
 * 2. 释放派生接口（CaptureClient）
 * 3. 释放基础接口（AudioClient）
 * 4. 释放格式信息
 * 5. 释放设备
 * 6. 释放枚举器
 * 
 * 注意：必须在创建这些对象的同一线程中释放（COM 线程亲和性）
 */
void AudioCapturer::cleanupWASAPI()
{
    // 步骤1：停止音频流
    if (m_audioClient) {
        m_audioClient->Stop();
    }

    // 步骤2：释放捕获客户端接口
    if (m_captureClient) {
        m_captureClient->Release();  // COM 对象的标准释放方法
        m_captureClient = nullptr;   // 防止悬空指针
    }

    // 步骤3：释放音频客户端接口
    if (m_audioClient) {
        m_audioClient->Release();
        m_audioClient = nullptr;
    }

    // 步骤4：释放音频格式信息
    // 注意：使用 CoTaskMemFree 而不是 delete，因为这是 COM 分配的内存
    if (m_waveFormat) {
        CoTaskMemFree(m_waveFormat);
        m_waveFormat = nullptr;
    }

    // 步骤5：释放设备接口
    if (m_device) {
        m_device->Release();
        m_device = nullptr;
    }

    // 步骤6：释放设备枚举器
    if (m_deviceEnumerator) {
        m_deviceEnumerator->Release();
        m_deviceEnumerator = nullptr;
    }
}

/**
 * 音频捕获主循环
 * 
 * 这是持续运行的循环，从 WASAPI 缓冲区读取音频数据
 * 
 * 工作流程：
 * 1. 检查是否有新的音频包
 * 2. 从缓冲区获取音频数据
 * 3. 处理音频数据（格式转换、声道混合）
 * 4. 发送信号到主线程
 * 5. 释放缓冲区
 * 
 * 循环直到收到停止请求（m_stopRequested = true）
 */
void AudioCapturer::captureLoop()
{
    HRESULT hr;
    BYTE *pData = nullptr;              // 指向音频数据的指针
    UINT32 packetLength = 0;            // 下一个数据包的大小
    UINT32 numFramesAvailable = 0;      // 可用的音频帧数
    DWORD flags = 0;                    // 数据包标志（静音等）

    // 主循环：持续捕获，直到收到停止请求
    while(!m_stopRequested)
    {
        // 短暂休眠，避免 CPU 占用过高
        Sleep(10);  // 10 毫秒
        
        // 检查下一个数据包的大小
        hr = m_captureClient->GetNextPacketSize(&packetLength);
        if (FAILED(hr)) {
            continue;  // 出错则跳过本次迭代
        }
        
        // 处理所有可用的数据包
        while(packetLength != 0)
        {
            // ========== 获取音频缓冲区 ==========
            // pData: 指向音频数据的指针
            // numFramesAvailable: 此数据包中的帧数
            // flags: 数据包标志
            hr = m_captureClient->GetBuffer(&pData, &numFramesAvailable,
                                           &flags, nullptr, nullptr);
            if(FAILED(hr)) {
                break;
            }

            // 检查静音标志
            if(flags & AUDCLNT_BUFFERFLAGS_SILENT) {
                pData = nullptr;  // 静音数据，不需要处理
            }

            // ========== 处理音频数据 ==========
            if (pData && numFramesAvailable > 0) {
                QVector<float> audioData;
                int channels = m_waveFormat->nChannels;      // 声道数（通常是 2）
                int sampleRate = m_waveFormat->nSamplesPerSec;  // 采样率

                // 根据位深度转换音频格式
                // 目标：转换为单声道（mono）、浮点格式（-1.0 到 1.0）
                
                // --- 32 位浮点格式 ---（最常见）
                if (m_waveFormat->wBitsPerSample == 32) {
                    float *floatData = (float*)pData;
                    for (UINT32 i = 0; i < numFramesAvailable; i++) {
                        float sum = 0.0f;
                        // 混合所有声道到单声道
                        for (int ch = 0; ch < channels; ch++) {
                            sum += floatData[i * channels + ch];
                        }
                        audioData.append(sum / channels);  // 平均值
                    }
                }
                // --- 16 位 PCM 格式 ---
                else if (m_waveFormat->wBitsPerSample == 16) {
                    short *shortData = (short*)pData;
                    for (UINT32 i = 0; i < numFramesAvailable; i++) {
                        float sum = 0.0f;
                        for (int ch = 0; ch < channels; ch++) {
                            // 转换范围：-32768~32767 → -1.0~1.0
                            sum += shortData[i * channels + ch] / 32768.0f;
                        }
                        audioData.append(sum / channels);
                    }
                }
                // --- 24 位 PCM 格式 ---（较少见）
                else if (m_waveFormat->wBitsPerSample == 24) {
                    BYTE *byteData = pData;
                    for (UINT32 i = 0; i < numFramesAvailable; i++) {
                        float sum = 0.0f;
                        for (int ch = 0; ch < channels; ch++) {
                            int byteOffset = (i * channels + ch) * 3;
                            // 读取 24 位值（小端序）
                            int value = byteData[byteOffset] | 
                                       (byteData[byteOffset + 1] << 8) | 
                                       (byteData[byteOffset + 2] << 16);
                            // 符号扩展（处理负数）
                            if (value & 0x800000) value |= 0xFF000000;
                            // 转换范围：-8388608~8388607 → -1.0~1.0
                            sum += value / 8388608.0f;  // 2^23
                        }
                        audioData.append(sum / channels);
                    }
                }

                // 👇 在子线程中处理FFT分析
                if (!audioData.isEmpty()) {
                    // 累积音频数据到缓冲区
                    m_audioBuffer.append(audioData);
                    m_sampleRate = sampleRate;
                    
                    // 限制缓冲区大小（保持约0.5秒的数据）
                    int maxBufferSize = m_sampleRate / 2;
                    if (m_audioBuffer.size() > maxBufferSize) {
                        // 删除最旧的数据，保留最新的数据
                        m_audioBuffer.remove(0, m_audioBuffer.size() - maxBufferSize);
                    }
                    
                    // 当缓冲区有足够数据时，执行FFT分析（在子线程中！）
                    if (m_audioBuffer.size() >= 2048 && m_spectrumAnalyzer) {
                        // 执行FFT和频谱计算
                        m_spectrumAnalyzer->processAudioData(m_audioBuffer, m_sampleRate);
                        
                        // 获取频谱数据
                        QVector<float> spectrum = m_spectrumAnalyzer->getSpectrum();
                        
                        // 发送频谱数据到主线程（不再发送原始音频）
                        emit spectrumReady(spectrum);
                    }
                }
            }

            // ========== 释放缓冲区 ==========
            // 必须释放，否则缓冲区会满
            hr = m_captureClient->ReleaseBuffer(numFramesAvailable);
            if (FAILED(hr)) {
                break;
            }

            // 检查下一个数据包
            hr = m_captureClient->GetNextPacketSize(&packetLength);
            if (FAILED(hr)) {
                break;
            }
        }
    }
}

